﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.Text.RegularExpressions;
using System.ComponentModel;
using System.Windows.Media.Animation;

namespace BluetoothPC
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        private delegate void showData(string msg); //通信窗口输出相关

        //private TcpClient client;
        private Socket server;

        //private NetworkStream sendStream;

        private const int bufferSize = 1024;
        private Thread thread;
        private Thread Updateth;
        private Thread StepCounting;

        BitmapImage bitmapImage1 = new BitmapImage(new Uri("/picture/1.png", UriKind.Relative));
        BitmapImage bitmapImage2 = new BitmapImage(new Uri("/picture/2.png", UriKind.Relative));

        private int valueNum = 5;
        //private double[] tempValue;
        private List<double> tempValue = new List<double>();
        private Boolean isDirectionUp = false;
        private int continueUpCount = 0;
        private int continueUpFormerCount = 0;
        private Boolean lastStatus = false;
        private double peakOfWave = 0;
        private double valleyOfWave = 0;
        private double timeOfThisPeak = 0;
        private double timeOfLastPeak = 0;
        private double timeOfNow = 0;
        private double gravityOld = 0;
        private double initialValue = 1.7;
        private double ThreadValue = 2.0;
        private double minValue = 11;
        private double maxValue = 19.6;
        private double g = 9.8;
        private double thisSteps = 0;   //当前步数

        private double StepsCopy = 0;   //步数复制

        private double X_axis = 0;
        private double Y_axis = 0;
        private double Z_axis = 0;





        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            //时间线程
            DispatcherTimer dateTimer = new DispatcherTimer();//显示当前时间线程
            dateTimer.Tick += new EventHandler(dateTimer_Tick);
            dateTimer.Interval = new TimeSpan(0, 0, 0, 1, 0);
            dateTimer.Start();

            //UDP监听线程
            thread = new Thread(ListenerServer);
            thread.IsBackground = true;

            //数据更新线程
            Updateth = new Thread(UpdateTextBox);
            Updateth.Start();

            //动态界面显示
            var delay = new TimeSpan(0);
            foreach (Ellipse item in Container1.Children)
            {
                var baseAnimation = Container1.Resources["MyAnimation"] as Storyboard;
                var storyBoard = baseAnimation.Clone();
                storyBoard.BeginTime = delay;
                item.BeginStoryboard(storyBoard);
                delay = delay.Add(TimeSpan.FromSeconds(0.1));
            }
            foreach (Ellipse item in Container2.Children)
            {
                var baseAnimation = Container2.Resources["MyAnimation"] as Storyboard;
                var storyBoard = baseAnimation.Clone();
                storyBoard.BeginTime = delay;
                item.BeginStoryboard(storyBoard);
                delay = delay.Add(TimeSpan.FromSeconds(0.1));
            }


        }

        private async void UpdateTextBox()
        {
            while (true)
            {
                Dispatcher.Invoke(() =>
                {
                    XaxisTextBox.Text = X_axis.ToString();
                    YaxisTextBox.Text = Y_axis.ToString();
                    ZaxisTextBox.Text = Z_axis.ToString();
                });

                await Task.Delay(100);
            }          
        }

        private void dateTimer_Tick(object sender, EventArgs e)//取当前时间的委托
        {
            string timeDateString = "";
            DateTime now = DateTime.Now;
            timeDateString = string.Format("{0}年{1}月{2}日 {3}:{4}:{5}",
                now.Year,
                now.Month.ToString("00"),
                now.Day.ToString("00"),
                now.Hour.ToString("00"),
                now.Minute.ToString("00"),
                now.Second.ToString("00"));

            timeDateTextBlock.Text = timeDateString;
            //statusInfoTextBlock.Text = Convert.ToInt64((DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0)).TotalMilliseconds).ToString();
        }

        private void Window_Closed(object sender, EventArgs e)
        {
            try
            {
                server.Close();
                server = null;
                server.Dispose();
            }
            catch
            {

            }
            
        }

        private void Switch_Button_Click(object sender, RoutedEventArgs e)
        {
            Button bt = sender as Button;
            

            if (bt.Content.ToString() == "请求连接")
            {
                //判断IP是否为空
                if (IPAdressTextBox.Text.Trim() == string.Empty)
                {
                    _ = new MessageWindow()
                    {
                        Owner = this,
                        Header = "警告",
                        Message = "请填入服务器IP地址"
                    }.ShowDialog();
                    //ComWinTextBox.Dispatcher.Invoke(new showData(ComWinTextBox.AppendText), "请填入服务器IP地址\n");
                    return;
                }
                //判断IP是否正确
                if (Regex.Matches(IPAdressTextBox.Text.Trim(), Regex.Escape(new string('.', 1))).Count != 3)
                {
                    _ = new MessageWindow()
                    {
                        Owner = this,
                        Header = "错误",
                        Message = "服务器IP地址无效"
                    }.ShowDialog();
                    //ComWinTextBox.Dispatcher.Invoke(new showData(ComWinTextBox.AppendText), "请填入服务器IP地址\n");
                    return;
                }

                //判断端口是否为空
                if (PortTextBox.Text.Trim() == string.Empty)
                {
                    _ = new MessageWindow()
                    {
                        Owner = this,
                        Header = "警告",
                        Message = "请填入服务器端口号"
                    }.ShowDialog();
                    //ComWinTextBox.Dispatcher.Invoke(new showData(ComWinTextBox.AppendText), "请填入服务器端口号\n");
                    return;
                }
                //判断端口是否能转成数字
                if (!Regex.IsMatch(PortTextBox.Text.Trim(), @"^[+-]?\d*[.]?\d*$"))
                {
                    _ = new MessageWindow()
                    {
                        Owner = this,
                        Header = "错误",
                        Message = "服务器端口号无效"
                    }.ShowDialog();
                    //ComWinTextBox.Dispatcher.Invoke(new showData(ComWinTextBox.AppendText), "请填入服务器端口号\n");
                    return;
                }
                else if (Convert.ToDouble(PortTextBox.Text.Trim()) > 65535)
                {
                    _ = new MessageWindow()
                    {
                        Owner = this,
                        Header = "错误",
                        Message = "服务器端口号无效"
                    }.ShowDialog();
                    //ComWinTextBox.Dispatcher.Invoke(new showData(ComWinTextBox.AppendText), "请填入服务器端口号\n");
                    return;
                }

                try
                {
                    IPAddress ip = IPAddress.Parse(IPAdressTextBox.Text);
                    //ComWinTextBox.AppendText("开始连接服务端....\n");

                    //client = new TcpClient();
                    server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                    //ComWinTextBox.AppendText("已经创建服务器....\n");

                    //client.Connect(ip, int.Parse(PortTextBox.Text));
                    server.Bind(new IPEndPoint(ip, int.Parse(PortTextBox.Text)));
                    //ComWinTextBox.AppendText("已经绑定客户端....\n");

                    //ComWinTextBox.AppendText("已经连接服务端\n");
                    statusInfoTextBlock.Text = "建立接收透传数据成功";

                    //sendStream = client.GetStream();

                    if (thread.ThreadState == ThreadState.Aborted)
                    {
                        thread = new Thread(ListenerServer);
                        thread.IsBackground = true;
                    }
                    if (thread.ThreadState == (ThreadState.Unstarted | ThreadState.Background))
                    {
                        thread.Start();
                    }

                    bt.Content = "断开连接";
                    imageBtn.Source = bitmapImage2;
                }
                catch
                {
                    _ = new MessageWindow()
                    {
                        Owner = this,
                        Header = "错误",
                        Message = "连接服务端失败"
                    }.ShowDialog();

                    //ComWinTextBox.AppendText("连接服务端失败\n");
                    statusInfoTextBlock.Text = "服务器未连接";
                }
            }
            else
            {
                thread.Abort();
                //sendStream.Close();
                server.Close();
                server = null;
                bt.Content = "请求连接";
                imageBtn.Source = bitmapImage1;

                //ComWinTextBox.AppendText("已与服务器断开连接\n");
                statusInfoTextBlock.Text = "已与服务器断开连接";
            }
        }

        private void ListenerServer()
        {
            do
            {
                try
                {
                    int readSize;
                    byte[] buffer = new byte[bufferSize];
                    EndPoint point = new IPEndPoint(IPAddress.Any, 0);

                    //lock (sendStream)
                    //{
                    //readSize = sendStream.Read(buffer, 0, bufferSize);
                    //}

                    readSize = server.ReceiveFrom(buffer, ref point);
                    
                    if (readSize == 0)return;

                    //16进制处理模式
                    //string receiveData = byteToHexStr(buffer, readSize);

                    string receiveDataDefault = Encoding.UTF8.GetString(buffer, 0, readSize);
                    double[] XYZ_axis = StringToDouble3(receiveDataDefault);
                    X_axis = XYZ_axis[0];
                    Y_axis = XYZ_axis[1];
                    Z_axis = XYZ_axis[2];

                    //ComWinTextBox.Dispatcher.Invoke(new showData(ComWinTextBox.AppendText), "信息：" + receiveDataDefault + " + " + receiveDataDefault.Length + "\n");
                    //ComWinTextBox.Dispatcher.Invoke(new showData(ComWinTextBox.AppendText), "信息：" + X_axis + " + " + Y_axis + " + " + Z_axis + "+" + thisSteps + "\n");

                }
                catch
                {
                    //ComWinTextBox.Dispatcher.Invoke(new showData(ComWinTextBox.AppendText), "接收数据错误\n");
                    //statusInfoTextBlock.Text = "接收数据发生错误";//用异步改写一下
                    //break;
                }

            } while (true);
        }

        /// <summary>
        /// 后期可能要删除
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        //private void ComWinTextBox_TextChanged(object sender, TextChangedEventArgs e)
        //{
        //    ComWinTextBox.ScrollToEnd(); //当通信窗口内容有变化时保持滚动条在最下面
        //}

        /// <summary>
        /// 接收字符转double数组
        /// 获取三轴加速度double值
        /// </summary>
        /// <param name="receive"></param>
        /// <returns></returns>
        public double[] StringToDouble3(string receive)
        {
            List<double> XYZacceleration = new List<double>();
            Regex rg = new Regex("(?<=(" + ":" + "))[.\\s\\S]*?(?=(" + "mG" + "))", RegexOptions.Multiline | RegexOptions.Singleline);
            MatchCollection results = rg.Matches(receive);

            foreach (Match result in results)
            {
                XYZacceleration.Add(Convert.ToDouble(result.Value) / 1000.0);
            }

            return XYZacceleration.ToArray();
        }

        /// <summary>
        /// 字节转字符串
        /// </summary>
        /// <param name="bytes"></param>
        /// <param name="readSize"></param>
        /// <returns></returns>
        public static string byteToHexStr(byte[] bytes, int readSize)
        {
            string returnStr = "";
            if (bytes != null)
            {
                for (int i = 0; i < readSize; i++)
                {
                    returnStr += bytes[i].ToString("X2");
                }
            }
            return returnStr;
        }
        /// <summary>
        /// 计步器x,y,z值由加速计获取
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="z"></param>
        public void counterStep(double x, double y, double z)
        {
            double _sqrt = Math.Sqrt(Math.Pow(x, 2) + Math.Pow(y, 2) + Math.Pow(z, 2));
            double _average = _sqrt * g;
            detectorNewStep(_average);
        }
        /// <summary>
        /// 监测新的步数 如果检测到了波峰，并且符合时间差以及阈值的条件，则判定为1步
        /// 符合时间差条件，波峰波谷差值大于initialValue，则将该差值纳入阈值的计算中
        /// </summary>
        /// <param name="_values">加速传感器三轴的平均值</param>
        public void detectorNewStep(double _values)
        {
            if (gravityOld == 0)
            {
                gravityOld = _values;
            }
            else
            {
                if (detectorPeak(_values, gravityOld))
                {
                    timeOfLastPeak = timeOfThisPeak;
                    timeOfNow = Convert.ToInt64((DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0)).TotalMilliseconds);
                    //时间差大于200ms，小于2s
                    if (((timeOfNow - timeOfLastPeak) >= 200) && ((timeOfNow - timeOfLastPeak) <= 2000) && ((peakOfWave - valleyOfWave) >= ThreadValue))
                    {
                        timeOfThisPeak = timeOfNow;
                        //增加步数
                        thisSteps++;
                        //增加步数复制
                        StepsCopy++;
                    }
                    if(((timeOfNow - timeOfLastPeak) >= 200) && ((peakOfWave - valleyOfWave) >= initialValue))
                    {
                        timeOfThisPeak = timeOfNow;
                        double _diffWaveVal = peakOfWave - valleyOfWave;
                        ThreadValue = peak_Valley_Thread(_diffWaveVal);
                    }
                }
                gravityOld = _values;
            }
        }
        /// <summary>
        /// 监测波峰
        /// 以下四个条件判断为波峰
        /// 1.目前点为下降的趋势：isDirectionUp为false
        /// 2.之前的点为上升的趋势：lastStatus为true
        /// 3.到波峰为止，持续上升大于等于2次
        /// 4.波峰值大于minValue,小于maxValue
        /// 记录波谷值
        /// 1.观察波形图，可以发现在出现步子的地方，波谷的下一个就是波峰，有比较明显的特征以及差值
        /// 2.所以要记录每次的波谷值，为了和下次的波峰作对比
        /// </summary>
        /// <param name="_newValue"></param>
        /// <param name="_oldValue"></param>
        /// <returns></returns>
        public Boolean detectorPeak(double _newValue, double _oldValue)
        {
            lastStatus = isDirectionUp;
            if (_newValue >= _oldValue)
            {
                isDirectionUp = true;
                continueUpCount++;
            }
            else
            {
                continueUpFormerCount = continueUpCount;
                continueUpCount = 0;
                isDirectionUp = false;
            }

            if (!isDirectionUp && lastStatus && (continueUpFormerCount >= 2 && (_oldValue >= minValue && _oldValue < maxValue)))
            {
                //满足上面波峰的四个条件，此时为波峰状态
                peakOfWave = _oldValue;
                return true;
            }
            else if (!lastStatus && isDirectionUp)
            {
                //满足波谷条件，此时为波谷状态
                valleyOfWave = _oldValue;
                return false;
            }
            else
            {
                return false;
            }
        }
        /// <summary>
        /// 阈值的计算
        /// 1.通过波峰波谷的差值计算阈值
        /// 2.记录4个值，存入tempValue[] 数组中
        /// 3.在将数组传入函数averageValue中计算阈值
        /// </summary>
        /// <param name="_value"></param>
        /// <returns></returns>
        public double peak_Valley_Thread(double _value)
        {
            double _tempThread = ThreadValue;
            List<double> _tempValue = new List<double>(tempValue);
            if (tempValue.Count < valueNum)
            {
                tempValue.Add(_value);
            }
            else
            {
                //tempValue数组长度=valueNum=5
                _tempThread = averageValue(tempValue);

                _tempValue.RemoveAt(0);
                _tempValue.Add(_value);
                tempValue = _tempValue;
            }
            return _tempThread;
        }
        /// <summary>
        /// 梯度化阈值
        /// 1.计算数组的均值
        /// 2.通过均值将阈值梯度化在一个范围里
        /// 这些数据是通过大量的统计得到的
        /// </summary>
        /// <param name="_value"></param>
        /// <returns></returns>
        public double averageValue(List<double> _value)
        {
            if (_value.Count != 0)
            {
                double _ave = 0;
                foreach (double i in _value)
                    _ave += i;
                _ave = _ave / _value.Count;
                if(_ave >= 8)
                {
                    _ave = 4.3;
                }
                else if (_ave >= 7 && _ave < 8)
                {
                    _ave = 3.3;
                }
                else if (_ave >= 4 && _ave < 7)
                {
                    _ave = 2.3;
                }
                else if (_ave >= 3 && _ave < 4)
                {
                    _ave = 2.0;
                }
                else
                {
                    _ave = 1.7;
                }
                return _ave;
            }
            else
            {
                return 1.7;
            }
        }

        private async void StepCountingMethod()
        {
            while (true)
            {
                counterStep(X_axis, Y_axis, Z_axis);
                
                if(StepsCopy >= 50)
                {
                    //清零
                    StepsCopy = 0;

                    Dispatcher.Invoke(new Action(() =>
                    {
                        //信息窗
                        new JumpPage()
                        {
                            NotifyMessage = "您已完成50步，加油!!!"
                        }.Show();
                    }));                  
                }

                //步数显示
                Dispatcher.Invoke(() =>
                {
                    StepNumberDisplay.Text = thisSteps.ToString();
                    MyBeautifulBar.Value = StepsCopy * 10;
                });

                await Task.Delay(100);
            }
        }

        private void ToggleButton_Checked(object sender, RoutedEventArgs e)
        {
            //ComWinTextBox.AppendText("开始计步\n");
            StepCounting = new Thread(StepCountingMethod);
            StepCounting.Start();

            //信息窗
            new JumpPage()
            {
                NotifyMessage = "开始计步!!!"
            }.Show();

        }

        private void ToggleButton_Unchecked(object sender, RoutedEventArgs e)
        {
            if(StepCounting.IsAlive == true)
            {
                StepCounting.Abort();
                //ComWinTextBox.AppendText("计步结束\n");
            }
            //步数清零
            thisSteps = 0;
            //步数副本清零
            StepsCopy = 0;

            //信息窗
            new JumpPage()
            {
                NotifyMessage = "计步结束!!!"
            }.Show();
        }

        //扩展按钮
        private void PseudoMaterializedButton3_Click(object sender, RoutedEventArgs e)
        {
            
        }

        private void PseudoMaterializedButton4_Click(object sender, RoutedEventArgs e)
        {
            
        }

        private void PseudoMaterializedButton2_Click(object sender, RoutedEventArgs e)
        {

        }

        private void PseudoMaterializedButton1_Click(object sender, RoutedEventArgs e)
        {

        }
    }
}
